package cn.buk.tms.eotms.dao;

import cn.buk.common.util.DateUtil;
import cn.buk.tms.common.constant.TmsOrderConstant;
import cn.buk.tms.eotms.dao.factory.OperationLogFactory;
import cn.buk.tms.eotms.entity.*;
import cn.buk.tms.eotms.sc.SearchFlightOrderCriteria;
import org.springframework.stereotype.Component;

import jakarta.persistence.EntityManager;
import jakarta.persistence.criteria.*;
import jakarta.transaction.Transactional;

import java.util.ArrayList;
import java.util.List;

import static cn.buk.tms.common.constant.TmsOrderConstant.*;

/**
 * @author yfdai
 */
@Component
@Transactional
public class FlightOrderDaoImpl extends AbstractDao implements FlightOrderDao {

    @Override
    public List<FlightOrder> searchOrder(final int ownerId, final int customerId, SearchFlightOrderCriteria sc) {
        List<FlightOrder> results = null;

        CriteriaBuilder cb = em.getCriteriaBuilder();
        CriteriaQuery<FlightOrder> cq = cb.createQuery(FlightOrder.class);
        Root<FlightOrder> root = cq.from(FlightOrder.class);
        root.alias("o");

        var predicates0 = getPredicates_searchOrder(ownerId, customerId, sc, cb, root, cq);

        //计算根据条件查询得出的数据总数
        CriteriaQuery<Long> countQuery = cb.createQuery(Long.class);
        Root<FlightOrder> countRoot = countQuery.from(FlightOrder.class);
        countRoot.alias("o");

        var predicates1 = getPredicates_searchOrder(ownerId, customerId, sc, cb, countRoot, cq);

        // count items
        countQuery.select(cb.count(countRoot))
                .where(predicates1.toArray(new Predicate[predicates1.size()]));
        Long count = em.createQuery(countQuery).getSingleResult();

        //查询
        cq.select(root).where(predicates0.toArray(new Predicate[predicates0.size()]));

        List<jakarta.persistence.criteria.Order> orderByes = new ArrayList<>();
        orderByes.add(cb.desc(root.get("id")));

        cq.orderBy(orderByes);

        int maxResults = count.intValue();
        if (maxResults > 0) {
            sc.getPage().setRowCount(maxResults);

            results = em.createQuery(cq)
                    .setFirstResult(sc.getPage().getFirstPosition())
                    .setMaxResults(sc.getPage().getPageSize())
                    .getResultList();

            for (FlightOrder order : results) {
                order.getFlights().size();
                order.getPassengers().size();
            }

        }
        if (results == null) {
            results = new ArrayList<>();
        }

        return results;
    }

    private List<Predicate> getPredicates_searchOrder(int ownerId, int customerId, SearchFlightOrderCriteria sc, CriteriaBuilder cb, Root<FlightOrder> root, CriteriaQuery<FlightOrder> cq) {
        List<Predicate> predicates = new ArrayList<>();

        Predicate predicate = cb.conjunction();
        predicates.add(predicate);

        predicate = cb.equal(root.get(FlightOrder_.enterpriseId), ownerId);
        predicates.add(predicate);

        predicate = cb.equal(root.get(FlightOrder_.customerId), customerId);
        predicates.add(predicate);

        if (sc.getStatus() > -1) {
            predicate = cb.equal(root.get(FlightOrder_.status), sc.getStatus());
            predicates.add(predicate);
        }

        if (sc.getApprover() != null && sc.getApprover().trim().length() > 0) {
            predicate = cb.equal(root.get(FlightOrder_.approvalInfo).get(OrderApprovalInfo_.specifiedApprover), sc.getApprover().trim());
            predicates.add(predicate);
        }

        if (sc.getBeginDate() != null) {
            predicate = cb.greaterThanOrEqualTo(root.get(FlightOrder_.createDate), sc.getBeginDate());
            predicates.add(predicate);
        }

        if (sc.getEndDate() != null) {
            predicate = cb.lessThanOrEqualTo(root.get(FlightOrder_.createDate), sc.getEndDate());
            predicates.add(predicate);
        }

        if (sc.getOp1().length() > 0) {
            //查找指定用户名的订单
            predicate = cb.equal(root.get(FlightOrder_.operator), sc.getOp1());
            predicates.add(predicate);
        }
        if (sc.getDepartmentId() != null) {
            //只查找本部门的
            //获取本部门的用户名
            List<String> usernames = doGetCustomerDepartmentOperator(ownerId, customerId, sc.getDepartmentId());

            Path<String> path = root.get(FlightOrder_.operator);
            CriteriaBuilder.In<String> in = cb.in(path);
            for (String username : usernames) {
                in.value(username);
            }

            predicates.add(in);
        }


        if (sc.getIntlTicket() >= 0) {
            predicate = cb.equal(root.get(FlightOrder_.intlTicket), sc.getIntlTicket());
            predicates.add(predicate);
        }

        if (sc.getLinkman().length() > 0) {
            predicates.add(cb.like(root.get(FlightOrder_.linkman), "%" + sc.getLinkman() + "%"));
        }

        if (sc.getLinkPhone().length() > 0) {
            predicates.add(cb.like(root.get(FlightOrder_.linkPhone), "%" + sc.getLinkPhone() + "%"));
        }

        if (sc.getPnrNo() != null && sc.getPnrNo().trim().length() > 4) {
            predicates.add(cb.equal(root.get(FlightOrder_.pnrNo), sc.getPnrNo()));
        }

        if (sc.getWorkStatus() == 1) {
            //只查看需要处理的订单
            predicate = cb.notEqual(root.get(FlightOrder_.status), TmsOrderConstant.FLIGHT_ORDER_STATUS_CANCELED);
            predicate = cb.and(predicate,
                    cb.notEqual(root.get(FlightOrder_.status), TmsOrderConstant.FLIGHT_ORDER_STATUS_TICKETED));
            predicate = cb.and(predicate,
                    cb.notEqual(root.get(FlightOrder_.status), TmsOrderConstant.FLIGHT_ORDER_STATUS_FINISHED));
            predicates.add(predicate);
        }

        if (sc.getOp1().length() > 0) {
            //只看指定预订员
            predicate = cb.equal(root.get(FlightOrder_.operator), sc.getOp1());
            predicates.add(predicate);
        }

        if (sc.getOrderNo().length() > 0) {
            //订单号
            predicate = cb.equal(root.get(FlightOrder_.orderNo), sc.getOrderNo());
            predicates.add(predicate);
        } else if (sc.getStatus() == -1) {
            //未指定订单号、订单状态，则不显示已取消的订单
            predicate = cb.notEqual(root.get(FlightOrder_.status), TmsOrderConstant.FLIGHT_ORDER_STATUS_CANCELED);
            predicates.add(predicate);
        }

        if (sc.getPnrNo() != null && sc.getPnrNo().trim().length() > 0) {
            //编码
            predicate = cb.equal(root.get(FlightOrder_.pnrNo), sc.getPnrNo().trim());
            predicates.add(predicate);
        }

        if (sc.getPayStatus() == 0) {
            predicate = cb.isNull(root.get(FlightOrder_.payStatus));
            predicate = cb.or(predicate, cb.equal(root.get(FlightOrder_.payStatus), 0));
            predicates.add(predicate);
        } else if (sc.getPayStatus() == 1) {
            predicate = cb.equal(root.get(FlightOrder_.payStatus), 1);
            predicate = cb.or(predicate, cb.equal(root.get(FlightOrder_.payStatus), 2));
            predicates.add(predicate);
        }

        Subquery<FlightOrderPassenger> subQuery = null;

        boolean b = sc.getName() != null && sc.getName().trim().length() > 0;
        b = b || (sc.getIdno() != null && sc.getIdno().trim().length() > 0);
        b = b || sc.getTicketNo().length() > 0;
        b = b || sc.getLinkman().length() > 0;
        b = b || sc.getLinkPhone().length() > 0;
        b = b || sc.getPhone().length() > 0;

        if (b) {
            subQuery = cq.subquery(FlightOrderPassenger.class);
            Root<FlightOrderPassenger> subRoot = subQuery.from(FlightOrderPassenger.class);
            subQuery.select(subRoot);
            subQuery.alias("s");

            List<Predicate> subQueryPredicates = new ArrayList<>();
            subQueryPredicates
                    .add(cb.equal(root.get(FlightOrder_.id), subRoot.get(FlightOrderPassenger_.order)));

            if (sc.getName() != null && sc.getName().trim().length() > 0) {
                subQueryPredicates
                        .add(cb.like(subRoot.get(FlightOrderPassenger_.name), "%" + sc.getName().trim() + "%"));
            }

            if (sc.getPhone().length() > 0) {
                subQueryPredicates
                        .add(cb.like(subRoot.get(FlightOrderPassenger_.mobile), "%" + sc.getPhone() + "%"));
            }

            if (sc.getIdno() != null && sc.getIdno().trim().length() > 0) {
                subQueryPredicates
                        .add(cb.like(subRoot.get(FlightOrderPassenger_.idNo), "%" + sc.getIdno().trim() + "%"));
            }

            if (sc.getTicketNo().length() > 0) {
                subQueryPredicates.add(
                        cb.like(subRoot.get(FlightOrderPassenger_.ticketNo), "%" + sc.getTicketNo() + "%"));
            }

            subQuery.where(subQueryPredicates.toArray(new Predicate[]{}));
        }

        if (subQuery != null) {
            predicates.add(cb.exists(subQuery));
        }

        if (sc.getFlightNo().length() > 0 || (sc.getDepartureDate() != null
                && sc.getDepartureDate().length() == 10)) {
            // 航班号，或起飞日期
            Subquery<FlightOrderFlight> subQuery1 = cq.subquery(FlightOrderFlight.class);
            Root<FlightOrderFlight> subRoot = subQuery1.from(FlightOrderFlight.class);
            subQuery1.select(subRoot);
            subQuery1.alias("f");

            List<Predicate> subQueryPredicates = new ArrayList<>();
            subQueryPredicates
                    .add(cb.equal(root.get(FlightOrder_.id), subRoot.get(FlightOrderFlight_.order)));

            if (sc.getFlightNo().length() > 0) {
                subQueryPredicates.add(
                        cb.equal(subRoot.get(FlightOrderFlight_.flight).get("flightNo"), sc.getFlightNo()));
            }

            if (sc.getDepartureDate() != null && sc.getDepartureDate().length() == 10) {
                subQueryPredicates.add(cb.equal(subRoot.get(FlightOrderFlight_.flight).get("departureDate"),
                        sc.getDepartureDate()));
            }

            subQuery1.where(subQueryPredicates.toArray(new Predicate[]{}));
            predicates.add(cb.exists(subQuery1));
        }
        return predicates;
    }


    @Override
    public List<FlightOrderFlight> searchFlightOrderFlights(int flightOrderId) {
        return em.createQuery(
                        "select o from FlightOrderFlight o where o.order.id = :orderId order by o.segOrder",
                        FlightOrderFlight.class)
                .setParameter("orderId", flightOrderId)
                .getResultList();
    }

    @Override
    public FlightOrder getOrderById(int orderId) {
        FlightOrder order = em.find(FlightOrder.class, orderId);
        if (order == null) {
            return null;
        }

        order.getPassengers().size();
        order.getFlights().size();

        order.setTickets(doGetFlightOrderTickets(em, orderId));

        return order;
    }

    private List<FlightOrderTicket> doGetFlightOrderTickets(EntityManager em, int orderId) {
        return em.createQuery("select o from FlightOrderTicket o " +
                        "where o.order.id = :orderId " +
                        "order by o.ddate, o.dtime", FlightOrderTicket.class)
                .setParameter("orderId", orderId)
                .getResultList();
    }

    @Override
    public FlightOrder getOrderByOrderNo(int ownerId, String orderNo) {
        List<FlightOrder> list = em.createQuery("select o from FlightOrder o where o.enterpriseId = :enterpriseId and o.orderNo = :orderNo", FlightOrder.class)
                .setParameter("enterpriseId", ownerId)
                .setParameter("orderNo", orderNo)
                .getResultList();
        return list.size() > 0 ? list.get(0) : null;
    }

    @Override
    public int createOrder(final FlightOrder o, final String username) {
        em.persist(o);

        String remark = "创建订单(" + o.getStatus() + ").";

        OperationLog log = createFlightOrderLog(o.getEnterpriseId(), o.getCustomer().getId(), o.getId(), username, remark);
        em.persist(log);

        return o.getId();
    }

    @Override
    public int createBlanketOrder(final int userId, final int ownerId, final int customerId, final FlightOrder flightOrder,
                                  final List<VasOrder> vasOrders, double totalAmount) {
        //主订单
        em.persist(flightOrder);

        Customer customer = em.find(Customer.class, customerId);
        User user = em.find(User.class, userId);

        BlanketOrder mainOrder = new BlanketOrder();
        mainOrder.setEnterpriseId(ownerId);
        mainOrder.setCustomer(customer);
        mainOrder.setUser(user);
        mainOrder.setTotalAmount(totalAmount);
        mainOrder.setActualOrderType(TmsOrderConstant.ORDER_TYPE_FLIGHT);
        mainOrder.setActualOrderId(flightOrder.getId());
        em.persist(mainOrder);

        mainOrder.setRootId(mainOrder.getId());
        em.merge(mainOrder);

        flightOrder.setBlanketOrderId(mainOrder.getId());
        em.merge(flightOrder);

        //子订单
        for (VasOrder vasOrder : vasOrders) {
            em.persist(vasOrder);

            BlanketOrder subOrder = new BlanketOrder();
            subOrder.setEnterpriseId(ownerId);
            subOrder.setCustomer(customer);
            subOrder.setUser(user);

            if (TieInProduct.INSURANCE == vasOrder.getProductType()) {
                subOrder.setActualOrderType(TmsOrderConstant.ORDER_TYPE_INSURANCE);
            } else {
                subOrder.setActualOrderType(TmsOrderConstant.ORDER_TYPE_SERVICE);
            }
            subOrder.setActualOrderId(vasOrder.getId());
            subOrder.setParentId(mainOrder.getId());
            em.persist(subOrder);

            subOrder.setRootId(mainOrder.getId());
            em.merge(subOrder);

            vasOrder.setBlanketOrderId(subOrder.getId());
            em.merge(vasOrder);
        }

        OperationLog log = OperationLog.createLog(ownerId, OPERATING_OBJECT_FLIGHT_ORDER);
        log.setOperator(user.getUsername());
        log.setContent("创建总订单");
        em.persist(log);

        return flightOrder.getId();

    }

    @Override
    public List<BlanketOrder> searchSubOrders(final int ownerId, final int blanketOrderId) {
//    BlanketOrder blanketOrder = em.find(BlanketOrder.class, blanketOrderId);

        return em.createQuery("select o from BlanketOrder  o" +
                        " where o.enterpriseId = :enterpriseId" +
                        " and (o.parentId = :parentId)", BlanketOrder.class)
                .setParameter("enterpriseId", ownerId)
                .setParameter("parentId", blanketOrderId)
                .getResultList();
    }

    @Override
    public BlanketOrder searchParentOrder(int ownerId, Integer blanketOrderId) {
        BlanketOrder blanketOrder = em.find(BlanketOrder.class, blanketOrderId);
        if (blanketOrder.getParentId() != null) {
            return em.find(BlanketOrder.class, blanketOrder.getParentId());
        } else {
            return null;
        }
    }

    @Override
    public int updateFlightOrderPaid(final int userId, final int orderId) {
        User user = em.find(User.class, userId);
        FlightOrder flightOrder = em.find(FlightOrder.class, orderId);
        final int customerId = flightOrder.getCustomer().getId();

        int retCode = em.createQuery("update FlightOrder o " +
                        "set o.payStatus = :payStatus, " +
                        "o.lastUpdate = :lastUpdate " +
                        "where o.id = :id and (o.payStatus is null or o.payStatus <> :payStatus)")
                .setParameter("id", orderId)
                .setParameter("payStatus", 1)
                .setParameter("lastUpdate", DateUtil.getCurDateTime())
                .executeUpdate();
        if (retCode != 1) {
            throw new RuntimeException("update flight order pay status failed.");
        }

        OperationLog log = OperationLog.createLog(flightOrder.getEnterpriseId(), OPERATING_OBJECT_FLIGHT_ORDER);
        log.setCustomerId(customerId);
        log.setOperator(user.getUsername());
        log.setOrderId(orderId);
        log.setContent("订单支付完成");
        em.persist(log);

        if (flightOrder.getBlanketOrderId() != null) {
            //有对应的总订单，查找是否有子订单
            List<BlanketOrder> subOrders = this.searchSubOrders(flightOrder.getEnterpriseId(), flightOrder.getBlanketOrderId());
            if (subOrders.size() > 0) {
                for (BlanketOrder subOrder : subOrders) {
                    if (subOrder.getActualOrderType() == TmsOrderConstant.ORDER_TYPE_INSURANCE) {
                        //保险订单
                        VasOrder vasOrder = em.find(VasOrder.class, subOrder.getActualOrderId());
                        vasOrder.setPayStatus(1);
                        vasOrder.setLastUpdate(DateUtil.getCurDateTime());
                        em.merge(vasOrder);

                        log = OperationLog.createLog(flightOrder.getEnterpriseId(), OPERATING_OBJECT_VAS_ORDER);
                        log.setCustomerId(customerId);
                        log.setOperator(user.getUsername());
                        log.setOrderId(subOrder.getActualOrderId());
                        log.setContent("与主订单(" + flightOrder.getOrderNo() + ")一起支付完成");
                        em.persist(log);
                    }
                }
            }

            BlanketOrder blanketOrder = em.find(BlanketOrder.class, flightOrder.getBlanketOrderId());
            blanketOrder.setPayStatus(1);
            em.merge(blanketOrder);
        }


        return retCode;
    }

    @Override
    public int submitFlightOrder(final int userId, final int orderId) {
        User user = em.find(User.class, userId);
        FlightOrder flightOrder = em.find(FlightOrder.class, orderId);
        if (flightOrder.getPayType() == PAY_TYPE_CASH
                && (flightOrder.getPayStatus() == null || flightOrder.getPayStatus() != PAY_STATUS_PAID)) {
            throw new RuntimeException("Flight order should be paid first.");
        }

        final int enterpriseId = flightOrder.getEnterpriseId();
        int customerId = 0;

        boolean needBeAudited = false;
        if (flightOrder.getCustomerType() == 1) {
            //企业客户
            needBeAudited = flightOrder.getCustomer().getApprovalTicket() == 1;
            customerId = flightOrder.getCustomer().getId();
        }

        int retCode = em
                .createQuery("update FlightOrder o set o.status = :newStatus, o.lastUpdate = :lastUpdate " +
                        "where o.id = :id and o.status = :oldStatus")
                .setParameter("id", orderId)
                .setParameter("oldStatus", TmsOrderConstant.FLIGHT_ORDER_STATUS_WAITING)
                .setParameter("newStatus", TmsOrderConstant.FLIGHT_ORDER_STATUS_SUBMITTED)
                .setParameter("lastUpdate", DateUtil.getCurDateTime())
                .executeUpdate();
        if (retCode != 1) {
            throw new RuntimeException("It failed to submit flight order.");
        }

        OperationLog log = OperationLog.createLog(enterpriseId, OPERATING_OBJECT_FLIGHT_ORDER);
        if (customerId > 0) {
            log.setCustomerId(customerId);
        }
        log.setOperator(user.getUsername());
        log.setOrderId(orderId);
        log.setContent("申请开票，待审批");
        em.persist(log);

        if (!needBeAudited) {
            // 无需审核
            retCode = em.createQuery("update FlightOrder o set " +
                            "o.status = :newStatus " +
                            "where o.id = :id and o.enterpriseId = :enterpriseId and o.status = :oldStatus")
                    .setParameter("id", orderId)
                    .setParameter("enterpriseId", enterpriseId)
                    .setParameter("oldStatus", TmsOrderConstant.FLIGHT_ORDER_STATUS_SUBMITTED)
                    .setParameter("newStatus", TmsOrderConstant.FLIGHT_ORDER_STATUS_WAIT_TICKETING)
                    .executeUpdate();
            if (retCode == 1) {
                log = OperationLog.createLog(enterpriseId, OPERATING_OBJECT_FLIGHT_ORDER);
                if (customerId > 0) {
                    log.setCustomerId(customerId);
                }
                log.setOperator(user.getUsername());
                log.setOrderId(orderId);
                log.setContent("审批通过，允许开票");
                em.persist(log);
                retCode = 2; // 等待开票
            }
        }

        return retCode;
    }

    @Override
    public int approveFlightOrder(int ownerId, int customerId, String username, int orderId, int denyCode, String denyReason) {
        int retCode = 0;
        if (denyCode == 0) {
            //审批通过
            retCode = em
                    .createQuery("update FlightOrder o set o.status = :newStatus, " +
                            "o.approvalInfo.approvalStatus = 1, " +
                            "o.lastUpdate = :lastUpdate " +
                            "where o.id = :id " +
                            "and o.enterpriseId = :enterpriseId " +
                            "and o.customer.id = :customerId " +
                            "and o.status = :oldStatus")
                    .setParameter("id", orderId)
                    .setParameter("enterpriseId", ownerId)
                    .setParameter("customerId", customerId)
                    .setParameter("oldStatus", TmsOrderConstant.FLIGHT_ORDER_STATUS_SUBMITTED)
                    .setParameter("newStatus", TmsOrderConstant.FLIGHT_ORDER_STATUS_WAIT_TICKETING)
                    .setParameter("lastUpdate", DateUtil.getCurDateTime())
                    .executeUpdate();

            if (retCode == 1) {
                OperationLog log = createFlightOrderLog(ownerId, customerId, orderId, username, "审批通过，允许开票");
                em.persist(log);
            }
        } else {
            //审批拒绝
            retCode = em
                    .createQuery("update FlightOrder o set o.status = :newStatus, " +
                            "o.approvalInfo.approvalStatus = 0, " +
                            "o.approvalInfo.approvalDenyCode = :denyCode, " +
                            "o.approvalInfo.approvalDenyReason = :denyReason, " +
                            "o.lastUpdate = :lastUpdate " +
                            "where o.id = :id " +
                            "and o.enterpriseId = :enterpriseId " +
                            "and o.customer.id = :customerId " +
                            "and o.status = :oldStatus")
                    .setParameter("id", orderId)
                    .setParameter("enterpriseId", ownerId)
                    .setParameter("customerId", customerId)
                    .setParameter("oldStatus", TmsOrderConstant.FLIGHT_ORDER_STATUS_SUBMITTED)
                    .setParameter("newStatus", TmsOrderConstant.FLIGHT_ORDER_STATUS_CANCELED)
                    .setParameter("denyCode", denyCode + "")
                    .setParameter("denyReason", denyReason)
                    .setParameter("lastUpdate", DateUtil.getCurDateTime())
                    .executeUpdate();

            if (retCode == 1) {
                OperationLog log = createFlightOrderLog(ownerId, customerId, orderId, username, "审批拒绝(" + denyReason + ")，订单取消");
                em.persist(log);
                retCode = 2;
            }
        }

        return retCode;
    }

    @Override
    public void appendFlightOrderLog(int enterpriseId, int orderId, String remark) {
        var log = createFlightOrderLog(enterpriseId, null, orderId, null, remark);
        em.persist(log);
    }

    private OperationLog createFlightOrderLog(int enterpriseId, Integer customerId, int orderId, String username,
                                              String remark) {
        OperationLog log = OperationLogFactory.createFlightOrderOperationLog();
        log.setEnterpriseId(enterpriseId);
        log.setCustomerId(customerId);
        log.setOrderId(orderId);
        log.setOperator(username);
        log.setContent(remark);
        return log;
    }


}
